package com.estun.backroundManagementService.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * @author yusiocng
 * @date 2022/1/13
 * @description aop日志打印
 */
@Aspect
@Component
@Slf4j
public class WebLogAspect {

    public WebLogAspect() {
    }


    /**
     * 定义请求日志切入点，其切入点表达式有多种匹配方式,这里是指定路径
     */
    @Pointcut("execution(public * com.estun.backroundManagementService.controller..*.*(..))")
    public void webLogPointcut() {
    }


    /**
     * 在执行方法前后调用Advice，这是最常用的方法，相当于@Before和@AfterReturning全部做的事儿
     *
     * @param pjp 切点
     * @return 堆栈
     * @throws Throwable 异常
     */
    @Around("webLogPointcut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String requestUrl = request.getRequestURL().toString();
        //token校验
        String xToken = request.getHeader("X-Token");
//        tokenValid(xToken, requestUrl);
        //打印请求的内容
        long startTime = System.currentTimeMillis();
        log.info("请求Url:{},请求方式:{},发起方ip: {},请求参数:{}",
                requestUrl, request.getMethod(), request.getRemoteAddr(), Arrays.toString(pjp.getArgs()));
        // pjp.proceed()：当我们执行完切面代码之后，还有继续处理业务相关的代码。proceed()方法会继续执行业务代码，并且其返回值，就是业务处理完成之后的返回值。
        Object ret = pjp.proceed();
        long costTime = System.currentTimeMillis() - startTime;
        if (costTime < 1000) {
            log.info("请求耗时：{}ms", costTime);
        } else {
            log.warn("【秒级请求】 请求耗时：{}ms", costTime);
        }
        // 处理完请求，返回内容
        log.info("请求返回:{}", ret);
        return ret;
    }

//    public void tokenValid(String token, String url) {
//        if (StringUtils.isBlank(token) ||
//                url.contains("/user/login") ||
//                url.contains("/user/logout")
//        ) {
//            return;
//        }
//        TokenUtils.checkToken(token);
//    }


    /**
     * 异常通知：
     * 1. 在目标方法非正常结束，发生异常或者抛出异常时执行
     * 2. 在异常通知中设置异常信息，并将其保存
     */
    @AfterThrowing(value = "webLogPointcut()", throwing = "throwable")
    public void doAfterThrowing(Throwable throwable) {
        // 保存异常日志记录
        log.error("发生异常时间：{}", LocalDateTime.now());
        log.error("抛出异常：{}", throwable.getMessage());
    }
}

